package org.springframework.security.config.annotation;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.config.Customizer;
import org.springframework.util.Assert;

import java.util.*;

/**
 * @author Dillon
 * @date 2024/7/4
 * @slogan 致敬大师 致敬未来的你
 * @desc security 抽象构建器的扩展抽象类，
 * 进一步简化了安全配置对象的构建过程，可以将多个配置应用于构建
 */
public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBuilder<O>> extends AbstractSecurityBuilder<O> {

	/**
	 * 日志对象
	 */
	private final Log logger = LogFactory.getLog(getClass());

	/**
	 * 待初始化的所有安全配置对象
	 */
	private final LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>> configurers = new LinkedHashMap<>();

	/**
	 * 记录在初始化中时增加的安全配置对象
	 * 这是因为安全配置对象在init过程中 会继续添加安全配置对象
	 */
	private final List<SecurityConfigurer<O, B>> configurersAddedInInitializing = new ArrayList<>();

	/**
	 * 共享对象Map
	 */
	private final Map<Class<?>, Object> sharedObjects = new HashMap<>();

	/**
	 * 标记是否允许同样类型的配置对象
	 */
	private final boolean allowConfigurersOfSameType;

	/**
	 * 初始化构建状态
	 */
	private BuildState buildState = BuildState.UNBUILT;

	/**
	 * 对象后置处理器
	 */
	private ObjectPostProcessor<Object> objectPostProcessor;

	/**
	 * 构造函数
	 *
	 * @param objectPostProcessor 对象的后处理器
	 */
	protected AbstractConfiguredSecurityBuilder(ObjectPostProcessor<Object> objectPostProcessor) {
		this(objectPostProcessor, false);
	}

	/**
	 * 构造函数
	 *
	 * @param objectPostProcessor        对象的后处理器
	 * @param allowConfigurersOfSameType 是否允许同样类型的配置类 默认不允许
	 */
	protected AbstractConfiguredSecurityBuilder(ObjectPostProcessor<Object> objectPostProcessor, boolean allowConfigurersOfSameType) {
		Assert.notNull(objectPostProcessor, "objectPostProcessor cannot be null");
		this.objectPostProcessor = objectPostProcessor;
		this.allowConfigurersOfSameType = allowConfigurersOfSameType;
	}

	/**
	 * 如果对象未构建执行构建 并获取构建对象
	 * 如果对象已后见 获取构建对象
	 *
	 * @return 构建完成对象
	 */
	public O getOrBuild() {
		// 对象构建 尝试获取构建对象 可能会抛出未构建完成异常
		if (!isUnbuilt()) {
			return getObject();
		}
		// 尝试执行并获取构建对象
		try {
			return build();
		} catch (Exception ex) {
			this.logger.debug("执行构建失败，返回空 异常为 ： ", ex);
			return null;
		}
	}

	/**
	 * 应用配置类逻辑
	 * 就是添加配置类到初始化列表中 并设置后处理器 设置类初始化建造类 就是当前类，方便配置类统一配置
	 * @param configurer 配置类
	 * @return 配置类
	 * @param <C> 配置类泛型
	 * @throws Exception 执行异常
	 */
	@Deprecated(since = "6.2", forRemoval = true)
	@SuppressWarnings("unchecked")
	public <C extends SecurityConfigurerAdapter<O, B>> C apply(C configurer) throws Exception {
		configurer.addObjectPostProcessor(this.objectPostProcessor);
		configurer.setBuilder((B) this);
		add(configurer);
		return configurer;
	}

	/**
	 * Applies a {@link SecurityConfigurer} to this {@link SecurityBuilder} overriding any
	 * {@link SecurityConfigurer} of the exact same class. Note that object hierarchies
	 * are not considered.
	 *
	 * @param configurer
	 * @return the {@link SecurityConfigurerAdapter} for further customizations
	 * @throws Exception
	 */
	public <C extends SecurityConfigurer<O, B>> C apply(C configurer) throws Exception {
		add(configurer);
		return configurer;
	}

	/**
	 * Applies a {@link SecurityConfigurerAdapter} to this {@link SecurityBuilder} and
	 * invokes {@link SecurityConfigurerAdapter#setBuilder(SecurityBuilder)}.
	 *
	 * @param configurer
	 * @return the {@link SecurityBuilder} for further customizations
	 * @throws Exception
	 * @since 6.2
	 */
	@SuppressWarnings("unchecked")
	public <C extends SecurityConfigurerAdapter<O, B>> B with(C configurer, Customizer<C> customizer) throws Exception {
		configurer.addObjectPostProcessor(this.objectPostProcessor);
		configurer.setBuilder((B) this);
		add(configurer);
		customizer.customize(configurer);
		return (B) this;
	}

	/**
	 * 设置共享对象 方便在配置过程中获取
	 *
	 * @param sharedType 对象Class
	 * @param object     对象
	 * @param <C>        对象类型
	 */
	@SuppressWarnings("unchecked")
	public <C> void setSharedObject(Class<C> sharedType, C object) {
		this.sharedObjects.put(sharedType, object);
	}

	/**
	 * 获取共享对象
	 *
	 * @param sharedType 对象Class
	 * @param <C>        泛型
	 * @return 对象类型
	 */
	@SuppressWarnings("unchecked")
	public <C> C getSharedObject(Class<C> sharedType) {
		return (C) this.sharedObjects.get(sharedType);
	}

	/**
	 * 获取所有的共享对象
	 *
	 * @return 共享对象Map
	 */
	public Map<Class<?>, Object> getSharedObjects() {
		return Collections.unmodifiableMap(this.sharedObjects);
	}

	/**
	 * 比较核心方法，向安全配置MAP中添加配置对象
	 *
	 * @param configurer 配置对象
	 * @param <C>        配置对象泛型
	 */
	@SuppressWarnings("unchecked")
	private <C extends SecurityConfigurer<O, B>> void add(C configurer) {
		Assert.notNull(configurer, "配置对象不能为空");
		// 获取配置对象class 作为key
		Class<? extends SecurityConfigurer<O, B>> clazz = (Class<? extends SecurityConfigurer<O, B>>) configurer.getClass();
		synchronized (this.configurers) {
			// 添加时判断，如果初始化完成，则不能再进行添加
			if (this.buildState.isConfigured()) {
				throw new IllegalStateException("初始化已完成 不能再添加配置对象" + configurer);
			}
			List<SecurityConfigurer<O, B>> configs = null;
			// 如果允许同一个class存在多个对象，则走if
			// 否则每次都是覆盖添加
			if (this.allowConfigurersOfSameType) {
				configs = this.configurers.get(clazz);
			}
			configs = (configs != null) ? configs : new ArrayList<>(1);
			configs.add(configurer);
			this.configurers.put(clazz, configs);
			// 如果在init方法执行时添加，则将该配置类放在 初始化过程添加列表中
			// init方法执行时会循环该list
			if (this.buildState.isInitializing()) {
				this.configurersAddedInInitializing.add(configurer);
			}
		}
	}

	/**
	 * 获取配置对象列表 如果不允许重复，则列表中只会存在一条记录
	 *
	 * @param clazz 配置对象class
	 * @param <C>   泛型
	 * @return 配置对象
	 */
	@SuppressWarnings("unchecked")
	public <C extends SecurityConfigurer<O, B>> List<C> getConfigurers(Class<C> clazz) {
		List<C> configs = (List<C>) this.configurers.get(clazz);
		if (configs == null) {
			return new ArrayList<>();
		}
		return new ArrayList<>(configs);
	}

	/**
	 * 获取配置对象列表 如果不允许重复，则列表中只会存在一条记录
	 * 同时移除  configurersAddedInInitializing 中的对象
	 *
	 * @param clazz clazz类
	 * @param <C>   配置泛型
	 * @return 移除列表
	 */
	@SuppressWarnings("unchecked")
	public <C extends SecurityConfigurer<O, B>> List<C> removeConfigurers(Class<C> clazz) {
		List<C> configs = (List<C>) this.configurers.remove(clazz);
		if (configs == null) {
			return new ArrayList<>();
		}
		removeFromConfigurersAddedInInitializing(clazz);
		return new ArrayList<>(configs);
	}

	/**
	 * 根据class获取配置类
	 * 如果发现多条，抛出异常
	 *
	 * @param clazz class类
	 * @param <C>   泛型
	 * @return 配置对象
	 */
	@SuppressWarnings("unchecked")
	public <C extends SecurityConfigurer<O, B>> C getConfigurer(Class<C> clazz) {
		List<SecurityConfigurer<O, B>> configs = this.configurers.get(clazz);
		if (configs == null) {
			return null;
		}
		Assert.state(configs.size() == 1, () -> "尝试通过类 " + clazz + "获取一条对象, 但是获取到 " + configs);
		return (C) configs.get(0);
	}

	/**
	 * Removes and returns the {@link SecurityConfigurer} by its class name or
	 * <code>null</code> if not found. Note that object hierarchies are not considered.
	 * @param clazz
	 * @return
	 */
	/**
	 * 根据class移除配置类 同时移除  configurersAddedInInitializing 中对象
	 * 如果发现多条，抛出异常
	 *
	 * @param clazz class类
	 * @param <C>   泛型
	 * @return 配置对象
	 */
	@SuppressWarnings("unchecked")
	public <C extends SecurityConfigurer<O, B>> C removeConfigurer(Class<C> clazz) {
		List<SecurityConfigurer<O, B>> configs = this.configurers.remove(clazz);
		if (configs == null) {
			return null;
		}
		removeFromConfigurersAddedInInitializing(clazz);
		Assert.state(configs.size() == 1,
				() -> "尝试通过类 " + clazz + "移除一条对象, 但是获取到 " + configs);
		return (C) configs.get(0);
	}

	/**
	 * 移除 初始化中添加的配置对象
	 *
	 * @param clazz class类
	 * @param <C>   泛型
	 */
	private <C extends SecurityConfigurer<O, B>> void removeFromConfigurersAddedInInitializing(Class<C> clazz) {
		this.configurersAddedInInitializing.removeIf(clazz::isInstance);
	}

	/**
	 * 设置对象的后置处理器
	 *
	 * @param objectPostProcessor 对象后置处理器
	 * @return 当前对象
	 */
	@SuppressWarnings("unchecked")
	public B objectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {
		Assert.notNull(objectPostProcessor, "objectPostProcessor cannot be null");
		this.objectPostProcessor = objectPostProcessor;
		return (B) this;
	}

	/**
	 * 执行对象的后置处理
	 *
	 * @param object 后置处理的对象
	 * @param <P>    泛型
	 * @return 后置处理对象
	 */
	protected <P> P postProcess(P object) {
		return this.objectPostProcessor.postProcess(object);
	}

	/**
	 * 执行安全类的构建
	 *
	 * @return 构建完成的安全类
	 * @throws Exception 执行异常
	 */
	@Override
	protected final O doBuild() throws Exception {
		synchronized (this.configurers) {
			this.buildState = BuildState.INITIALIZING;
			beforeInit();
			init();
			this.buildState = BuildState.CONFIGURING;
			beforeConfigure();
			configure();
			this.buildState = BuildState.BUILDING;
			O result = performBuild();
			this.buildState = BuildState.BUILT;
			return result;
		}
	}

	/**
	 * 初始化前置方法，子类实现执行额外处理
	 *
	 * @throws Exception 执行异常
	 */
	protected void beforeInit() throws Exception {
	}

	/**
	 * 配置前置方法 子类实现执行额外处理
	 *
	 * @throws Exception 执行异常
	 */
	protected void beforeConfigure() throws Exception {
	}

	/**
	 * 执行构建对象 子类实现具体逻辑
	 *
	 * @return 构建好的对象
	 * @throws Exception 执行有慈航
	 */
	protected abstract O performBuild() throws Exception;

	/**
	 * 配置对象初始化
	 * 执行完成正常 init 后，执行 configurersAddedInInitializing(init 过程中添加的对象) init
	 *
	 * @throws Exception 执行异常
	 */
	@SuppressWarnings("unchecked")
	private void init() throws Exception {
		Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
		for (SecurityConfigurer<O, B> configurer : configurers) {
			configurer.init((B) this);
		}
		for (SecurityConfigurer<O, B> configurer : this.configurersAddedInInitializing) {
			configurer.init((B) this);
		}
	}

	/**
	 * 执行对象配置方法
	 *
	 * @throws Exception 执行异常
	 */
	@SuppressWarnings("unchecked")
	private void configure() throws Exception {
		Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
		for (SecurityConfigurer<O, B> configurer : configurers) {
			configurer.configure((B) this);
		}
	}

	/**
	 * 获取所有的安全配置对象
	 *
	 * @return 配置对象列表 如果存在相同的配置类对象 则全部获取
	 */
	private Collection<SecurityConfigurer<O, B>> getConfigurers() {
		List<SecurityConfigurer<O, B>> result = new ArrayList<>();
		for (List<SecurityConfigurer<O, B>> configs : this.configurers.values()) {
			result.addAll(configs);
		}
		return result;
	}

	/**
	 * 返回安全对象是否未开始执行初始化
	 *
	 * @return 配置对象是否未开始初始化
	 */
	private boolean isUnbuilt() {
		synchronized (this.configurers) {
			return this.buildState == BuildState.UNBUILT;
		}
	}

	/**
	 * 定义内部构建状态枚举类
	 */
	private enum BuildState {

		/**
		 * 标记当前类还未开始构建
		 */
		UNBUILT(0),

		/**
		 * 标识当前类在初始化中 调用 {@link SecurityConfigurer#init(SecurityBuilder)}
		 */
		INITIALIZING(1),

		/**
		 * 标记安全类在配置中 {@link SecurityConfigurer#configure(SecurityBuilder)}
		 */
		CONFIGURING(2),

		/**
		 * 标记安全类在构建中
		 */
		BUILDING(3),

		/**
		 * 标记类已经构建完成
		 */
		BUILT(4);

		/**
		 * 构建状态
		 */
		private final int order;

		/**
		 * 构造函数
		 *
		 * @param order 构建状态
		 */
		BuildState(int order) {
			this.order = order;
		}

		/**
		 * 判断安全对象是否在初始化中
		 *
		 * @return 是否在初始化中
		 */
		public boolean isInitializing() {
			return INITIALIZING.order == this.order;
		}

		/**
		 * 判断安全对象是否在配置中或者配置完成
		 *
		 * @return 是否在配置中 或者配置完成
		 */
		public boolean isConfigured() {
			return this.order >= CONFIGURING.order;
		}

	}

}
